using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ParaSharpNeatLib;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;

namespace WorkerGUI
{
    /// <summary>
    /// This form will load all the plug-in RemoteNetworkEvaluator's and allow the
    /// user to select one to start.  When an evaluator is running, it will display the
    /// number of evaluations remaining in its current job as well as the number of total
    /// evaluations its performed since intialization.
    /// </summary>
    public partial class Form1 : Form
    {
        AvailablePlugin<IRemoteNetworkEvaluator> selected;
        RemoteNetworkEvaluator running = null;
        TcpChannel channel;
        int networksEvaluated = 0;
        int batch = 0;
        private delegate void IncrementEvaluationCountDelegate();
        private delegate void SetBatchTextDelegate(int batchSize);

        public Form1()
        {
            InitializeComponent();
            PluginServices.Instance.FindPlugins();
            foreach (AvailablePlugin<IRemoteNetworkEvaluator> plug in PluginServices.Instance.AvailablePlugins)
            {
                IRemoteNetworkEvaluator rne = plug.Instance;
                TreeNode node = new TreeNode(rne.Name);
                node.Tag = plug;
                treePlugins.Nodes.Add(node);
            }
            if (treePlugins.Nodes.Count > 0)
            {
                selected = (AvailablePlugin<IRemoteNetworkEvaluator>)treePlugins.Nodes[0].Tag;
                lblName.Text = selected.Instance.Name;
                txtAuthor.Text = selected.Instance.Author;
                txtDescription.Text = selected.Instance.Description;
                txtVersion.Text = selected.Instance.Version;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            // Initialize the evaluator and get ready to roll
            selected.Instance.Initialize();

            // Create a channel to exchange data between the
            // server and client
            channel = new TcpChannel(51050);
            ChannelServices.RegisterChannel(channel, false);

            // Register to receive updates that we will display in our GUI
            ((RemoteNetworkEvaluator)selected.Instance).EvaluatedNetworkEvent += 
                            new RemoteNetworkEvaluator.EvaluatedNetworkEventHandler(Form1_EvaluatedNetworkEvent);
            ((RemoteNetworkEvaluator)selected.Instance).EvaluatingNetworksEvent +=
                            new RemoteNetworkEvaluator.EvaluatingNetworksEventHandler(Form1_EvaluatingNetworksEvent);

            // After the channel is registered, the object needs to be     
            // registered with the remoting infrastructure.  So,
            // Marshal is called
            RemotingServices.Marshal((RemoteNetworkEvaluator)selected.Instance, "RemoteNetworkEvaluator");

            running = (RemoteNetworkEvaluator)selected.Instance;

            button1.Enabled = false;
            button2.Enabled = true;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            RemotingServices.Disconnect(running);
            ChannelServices.UnregisterChannel(channel);

            button1.Enabled = true;
            button2.Enabled = false;
            batch = 0;
            networksEvaluated = 0;
        }

        private void treePlugins_AfterSelect(object sender, TreeViewEventArgs e)
        {
            selected = (AvailablePlugin<IRemoteNetworkEvaluator>)e.Node.Tag;
            lblName.Text = selected.Instance.Name;
            txtAuthor.Text = selected.Instance.Author;
            txtDescription.Text = selected.Instance.Description;
            txtVersion.Text = selected.Instance.Version;
        }

        private void Form1_EvaluatedNetworkEvent(object sender, EvaluatedNetworkEventArgs args)
        {
            this.BeginInvoke(new IncrementEvaluationCountDelegate(IncrementEvaluationCount));
        }

        private void IncrementEvaluationCount()
        {
            networksEvaluated++;
            txtNetworksEvaluated.Text = networksEvaluated.ToString();
            batch--;
            txtBatch.Text = batch.ToString();
        }

        private void Form1_EvaluatingNetworksEvent(object sender, EvaluatingNetworksEventArgs args)
        {
            this.BeginInvoke(new SetBatchTextDelegate(SetBatchText), args.Networks.Count);
        }

        private void SetBatchText(int batchSize)
        {
            batch = batchSize;
            txtBatch.Text = batch.ToString();
        }
    }
}